import {
  fromEvent,
  debounce,
  interval,
  map,
  timer,
  debounceTime,
  throttleTime,
  throttle,
  from,
  distinct,
  of,
  filter,
  first,
  skip,
  audit,
  distinctUntilChanged,
  distinctUntilKeyChanged,
  elementAt,
  ignoreElements,
  sampleTime,
  sample,
  skipUntil,
  skipWhile,
} from "rxjs";

export function skipUntilDemo() {
  // 设置一个触发条件，当点击文档的时候，后面的物料在进行，之前的都抛弃掉
  const click$ = fromEvent(document, "click");

  interval(1000)
    .pipe(skipUntil(click$))
    .subscribe((x) => console.log(x));

  const source = from([
    "Green Arrow",
    "SuperMan",
    "zyy",
    "SuperGirl",
    "zyy",
    "Black Canary",
  ]);

  // 把zyy前面的数据干掉
  source
    .pipe(
      skipWhile((val) => {
        return val !== "zyy";
      }),
    )
    .subscribe((x) => console.log(x));


  // 同理相同的还有 take, takeLast, takeUntil, takeWhile
  // 都是一样的，从跳过变成了拿
}

export function sameTimeDemo() {
  fromEvent(document, "click")
    .pipe(sampleTime(700))
    .subscribe((x) => console.log(x));

  // 处理一些高频事件，比如 mouseover； 我们希望0.5 s后拿到当前鼠标的坐标

  // fromEvent(document, "mouseover")
  //   .pipe(
  //     map((ev: Event) => {
  //       const x = (<MouseEvent>ev).clientX;
  //       const y = (<MouseEvent>ev).clientY;
  //       return {
  //         x,
  //         y,
  //       };
  //     }),
  //     sampleTime(500),
  //   )
  //   .subscribe((x) => console.log(x));
  //

  // 用sample也是可以实现的
  const redDeom = document.getElementById("red");

  if (redDeom === null) {
    return;
  }

  fromEvent(redDeom, "mouseover")
    .pipe(
      map((ev: Event) => {
        const x = (<MouseEvent>ev).clientX;
        const y = (<MouseEvent>ev).clientY;
        return {
          x,
          y,
        };
      }),
      sample(interval(500)),
    )
    .subscribe((x) => console.log(x));
}

export function ignoreElementDemo() {
  of("you", "talking", "to", "me")
    .pipe(ignoreElements()) // 取消所有物料
    .subscribe({
      next: (word) => console.log(word),
      error: (err) => console.log("error:", err),
      complete: () => console.log("the end"),
    });
}

export function elementAtDemo() {
  // 比如取第3次 document 的点击，前两次不用以及后面点击都不启作用;
  fromEvent(document, "click")
    .pipe(elementAt(2))
    .subscribe((x) => console.log(x));

  // 前两次不用以及后面点击都不启作用，后面点才可以
  // fromEvent(document, "click")
  // .pipe(skip(2))
  // .subscribe((x) => console.log(x));
}

// 当条件为true是不触发，当为flase时触发；主要功能和distinct
// 功能一样，用来去重；
export function distinctUntilChangedDemo() {
  of(1, 1, 1, 2, 2, 2, 1, 1, 3, 3)
    .pipe(distinctUntilChanged())
    .subscribe((x) => console.log(x)); // 1 2 1 3; 遇到相同的跳过

  const source$ = of(
    { id: 1, name: "Alice" },
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" },
    { id: 2, name: "Bob" },
    { id: 3, name: "Charlie" },
  );

  // 把上面说明name相同的过滤掉
  source$
    .pipe(
      distinctUntilChanged((prevObj, newObj) => {
        return prevObj.name === newObj.name;
      }),
    )
    .subscribe((x) => console.log(x));

  // 以上还有一种简单的写法，如下：
  source$
    .pipe(distinctUntilKeyChanged("name")) // 这里面直接传个key
    .subscribe((x) => console.log(x));
}

// 做一个点击事件，使用的是最后一次点击事件, 感觉和debounce 是一样的;
// 类似的还有个auditTime
export function auditDemo() {
  fromEvent(document, "click")
    .pipe(
      audit((ev) => interval(1000)),
      map((ev) => ev.target),
    )
    .subscribe((x) => {
      console.log(x);
    });
}

// ---------以下是必须要掌握并熟练应用------------------------------
// 跳过前10条数据
export function skipDemo() {
  // skip 跳出前几个数据
  interval(500)
    .pipe(skip(10))
    .subscribe((x) => {
      console.log(x);
    });
}

// first 获取第一个元素 last 是获取最后一个元素
export function firstAndLastDemo() {
  fromEvent(document, "click")
    .pipe(
      first((event) => {
        return (<HTMLElement>event.target).tagName === "DIV";
      }),
      map((event) => event.target),
    )
    .subscribe((x) => {
      console.log(x);
    });
}

export function filterDemo() {
  const div = document.createElement("div");
  div.style.cssText = "width: 200px; height: 200px; background: #09c;";
  document.body.appendChild(div);

  // 做了个事件委托的功能，把事件注册在
  // document上的，但是在在执行的时候只有点击到div上才能subscribe;
  fromEvent(document, "click")
    .pipe(filter((ev: Event) => (<HTMLElement>ev.target).tagName === "DIV"))
    .subscribe((x) => {
      console.log(x);
    });
}

// 去重
export const distinctDemo = () => {
  const arr = [
    { age: 4, name: "Foo" },
    { age: 7, name: "Bar" },
    { age: 5, name: "Foo" },
  ]; // 把name 相同的去掉
  const fromObs = from(arr);

  fromObs.pipe(distinct((item) => item.name)).subscribe((x) => {
    console.log(x);
  });

  of(1, 1, 2, 2, 2, 1, 2, 3, 4, 3, 2, 1)
    .pipe(distinct())
    .subscribe((x) => console.log(x)); // 1 2 3 4 , 直接去掉
};

// 节流处理，一般用在click 事件，只在第一次的触发；
export function throttleDemo() {
  const click$ = fromEvent(document, "click");

  // click$.pipe(throttleTime(3000)).subscribe((x) => {
  //   console.log(x);
  // });
  //
  click$.pipe(throttle(() => interval(2000))).subscribe((x) => {
    console.log(x);
  });
}

// dobounce 本意是抖动的意思，主要是接收最后一个物料，比如用在 input 事件和
// resize 事件中使用；
export function debounceDemo() {
  const resize$ = fromEvent(window, "resize");

  // resize$
  //   .pipe(
  //     map(() => ({
  //       with: window.innerWidth,
  //       heigh: window.innerHeight,
  //     })),
  //     debounce(() => interval(300)), // 300ms 触发一次,
  //     可以使用debounceTime，只不过这里面是个函数，可以做一些业务处理
  //   )
  //   .subscribe((x) => {
  //     console.log(x);
  //   });

  // 上和面的效果一样
  resize$
    .pipe(
      map(() => ({
        with: window.innerWidth,
        heigh: window.innerHeight,
      })),
      debounceTime(300),
    )
    .subscribe((x) => {
      console.log(x);
    });
}
